﻿/*
 *  Copyright (c) 2009 Alessandro Pilotti
 *
 *  Permission is hereby granted, free of charge, to any person
 *  obtaining a copy of this software and associated documentation
 *  files (the "Software"), to deal in the Software without
 *  restriction, including without limitation the rights to use,
 *  copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following
 *  conditions:
 *  
 *  The above copyright notice and this permission notice shall be
 *  included in all copies or substantial portions of the Software.
 *  
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 *  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 *  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 *  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *  OTHER DEALINGS IN THE SOFTWARE.
 */

using System.Text;
using AlexPilotti.DPAPI;

namespace AlexPilotti.KeyStorageManager
{
    public abstract class DPAPIKeyStorageProvider : IKeyStorageProvider
    {
        #region Private Data

        byte[] entropy = null;
        DPAPIWrapper.Store store = DPAPIWrapper.Store.User;

        #endregion

        #region Public Properties

        /// <summary>
        /// DPAI store to be used. Set to the user store by default;
        /// </summary>
        public DPAPIWrapper.Store Store
        {
            get { return store; }
            set { store = value; }
        }

        /// <summary>
        /// Optional entropy used in DPAPI calls.
        /// </summary>
        public byte[] Entropy
        {
            get { return entropy; }
            set { entropy = value; }
        }

        #endregion

        #region Abstract Methods

        protected abstract void StoreData(string name, byte [] secret);
        protected abstract byte[] LoadData(string name);
        protected abstract bool DeleteData(string name);

        #endregion

        #region IKeyStorageProvider Members

        public void StoreKey(string name, byte[] secret)
        {
            byte [] encryptedSecret = DPAPIWrapper.Encrypt(secret, entropy, store);
            StoreData(name, encryptedSecret);
        }

        public void StoreKey(string name, string secret)
        {
            StoreKey(name, Encoding.UTF8.GetBytes(secret));
        }

        public byte[] RetrieveKey(string name)
        {
            byte[] encryptedSecret = LoadData(name);
            return encryptedSecret != null ? DPAPIWrapper.Decrypt(encryptedSecret, entropy, store) : null;
        }

        public string RetrieveKeyAsString(string name)
        {
            byte[] data = RetrieveKey(name);
            return data != null ? Encoding.UTF8.GetString(data) : null;
        }

        public bool DeleteKey(string name)
        {
            return DeleteData(name);
        }

        #endregion
    }
}
